package main

import (
	"bytes"
	"common"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"
)

// openapi地址
var OPENAPI_BASE_URL = "https://api.su.baidu.com/"

// 签名算法
var SIGN_METHOD = "HMAC-SHA1"

//设置公共参数
func getInitedCommonParamsMap(ak string, authPathInfo string) map[string]string {
	authTimestamp := strconv.FormatInt(time.Now().Unix(), 10)
	paramMap := map[string]string{
		"X-Auth-Access-Key":       ak,
		"X-Auth-Nonce":            authTimestamp,
		"X-Auth-Path-Info":        authPathInfo,
		"X-Auth-Signature-Method": SIGN_METHOD,
		"X-Auth-Timestamp":        authTimestamp,
	}
	return paramMap
}

//排序并拼接参数
func getParsedAllParams(paramMap map[string]string) string {
	var paramList []string
	for k, v := range paramMap {
		var buffer bytes.Buffer
		buffer.WriteString(k)
		buffer.WriteString("=")
		buffer.WriteString(v)
		paramList = append(paramList, buffer.String())
	}
	sort.Strings(paramList)
	return strings.Join(paramList, "&")
}

//获取请求的header
func getRequestHeader(ak string, sk string, path string, bizParamsMap map[string]string) map[string]string {
	commonParamsMap := getInitedCommonParamsMap(ak, path)
	allParamsMap := make(map[string]string)
	headersMap := make(map[string]string)
	for k, v := range commonParamsMap {
		headersMap[k] = v
	}
	for k, v := range commonParamsMap {
		allParamsMap[k] = v
	}
	for k, v := range bizParamsMap {
		allParamsMap[k] = v
	}
	allParamsStr := getParsedAllParams(allParamsMap)
	sign := getSignature(sk, allParamsStr)
	headersMap["X-Auth-Sign"] = sign
	return headersMap
}

//发送http请求
func request(method string, path string, bizParamsMap map[string]string, headers map[string]string) map[string]interface{} {
	url := OPENAPI_BASE_URL + path
	params, _ := json.Marshal(bizParamsMap)
	payload := strings.NewReader(string(params))
	req, _ := http.NewRequest(method, url, payload)
	for k, v := range headers {
		req.Header.Add(k, v)
	}
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	return common.Str2Map(string(body))
}

//计算签名
func getSignature(secKey string, text string) string {
	key := []byte(secKey)
	mac := hmac.New(sha1.New, key)
	mac.Write([]byte(text))
	return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

//检查子域名是否存在
func checkSubDomain(ak string, sk string, domain string, subdomain string) map[string]interface{} {
	path := "v3/yjs/zones/dns_records"
	paramMap := map[string]string{
		"domain":    domain,
		"subdomain": subdomain,
	}
	headersMap := getRequestHeader(ak, sk, path, paramMap)
	return request("GET", path, paramMap, headersMap)
}

//创建子域名
func createSubDomain(ak string, sk string, domain string, subdomain string) map[string]interface{} {
	path := "v3/yjs/zones/dns_records"
	content := common.GetPubIp()
	paramMap := map[string]string{
		"domain":    domain,
		"subdomain": subdomain,
		"type":      "A",
		"content":   content.(string),
		"ttl":       "300",
		"isp_uuid":  "default",
	}
	headersMap := getRequestHeader(ak, sk, path, paramMap)
	return request("POST", path, paramMap, headersMap)
}

//更新子域名
func updateSubDomain(ak string, sk string, domain string, subdomain string, content string) map[string]interface{} {
	path := "v3/yjs/zones/dns_records"
	pubIp := common.GetPubIp()
	paramMap := map[string]string{
		"domain":       domain,
		"subdomain":    subdomain,
		"type":         "A",
		"content":      content,
		"isp_uuid":     "default",
		"new_content":  pubIp.(string),
		"new_isp_uuid": "default",
		"new_proxied":  "0",
	}
	headersMap := getRequestHeader(ak, sk, path, paramMap)
	return request("PUT", path, paramMap, headersMap)
}
func getCheckIp(data []interface{}) string {
	var ip = ""
	for _, v := range data {
		val := v.(map[string]interface{})
		rType := val["type"].(string)
		if rType == "A" {
			ip = val["content"].(string)
		}
	}
	return ip
}
func main() {
	var ak, sk, domain string
	flag.StringVar(&ak, "ak", "", "ACCESS_KEY，账户信息中获取")
	flag.StringVar(&sk, "sk", "", "SECRET_KEY，账户信息中获取")
	flag.StringVar(&domain, "domain", "", "需要设置的域名")
	flag.Parse()
	flag.Usage = usage
	if ak == "" || sk == "" || domain == "" {
		flag.Usage()
		return
	}
	mdomain, subdomain := common.ParseDomain(domain)
	var res = checkSubDomain(ak, sk, mdomain, subdomain)
	var check_result = res["result"].([]interface{})
	if len(check_result) == 0 {
		res = createSubDomain(ak, sk, mdomain, subdomain)
		var arr []interface{}
		item := res["result"].(map[string]interface{})
		check_result = append(arr, item)
	}
	ip := getCheckIp(check_result)
	update_result := updateSubDomain(ak, sk, mdomain, subdomain, ip)
	result_content := update_result["result"].(map[string]interface{})
	if result_content["content"] == "" || result_content["content"] == nil {
		fmt.Println("")
	} else {
		fmt.Println(result_content["content"])
	}
}
func usage() {
	fmt.Println("Usage: baidu_ddns -ak ACCESS_TOKEN -sk SECRET_TOKEN -domain DOMAIN")
	flag.PrintDefaults()
}
